﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ATEC.GeometryNET;
using SSDPNET.Geom;

using SSDPNET.DataCore;
using SSDPNET.ATDimObj;
using ATEC.ATDataCoreNET;
using ATEC.ATDataCoreNET.ATObjects;
using ATEC.ATDataCoreNET.ATCCL;
using ATEC.ATCore;


namespace DimensionExample
{
    /// <summary>
    /// //尺寸标注对象的构造函数会调用DimensionCreateData的各个成员函数去获取创建尺寸标注对象需要的各种参数
    /// </summary>
    public class DimensionProperty : DimensionCreateData
    {
        public DimensionStyle m_dimstyle;
        public ATTextStyle m_textStyle = null;
        public Symbology m_symbology;
        public LevelId m_levelId;
        public XMatrix3d m_dimMatrix;
        public XMatrix3d m_viewMatrix;

        /// <summary>
        /// 增加默认构造函数
        /// </summary>
        public DimensionProperty()
        {

        }

        public DimensionProperty(DimensionStyle dimstyle, ATTextStyle textstyle, Symbology symb, LevelId levelId, XMatrix3d rot1, XMatrix3d rot2)
        {
            m_dimstyle = dimstyle;
            m_textStyle = textstyle;
            m_symbology = symb;
            m_levelId = levelId;
            m_dimMatrix = rot1;
            m_viewMatrix = rot2;
        }
        public override XMatrix3d GetDimensionRotation()
        {
            return m_dimMatrix;
        }

        public override DimensionStyle GetDimensionStyle()
        {
            return m_dimstyle;
        }

        public override DirectionFormatter GetDirectionFormatter()
        {
            ATSceneRef sceneref = SSDPNET.ScenesFunctions.SceneRefGetActive();
            DirectionFormatter dirFormatter = new DirectionFormatter(sceneref.GetATScene());
            return dirFormatter;
        }

        public override LevelId GetLevelId()
        {
            return m_levelId;
        }

        public override Symbology GetSymbology()
        {
            return m_symbology;
        }

        public override ATTextStyle GetTextStyle()
        {
            return m_textStyle;
        }

        public override int GetViewNumber()
        {
            return 0;
        }

        public override XMatrix3d GetViewRotation()
        {
            return m_viewMatrix;
        }
    }

    /// <summary>
    /// 分类：玄镜BIM图形平台/C#开发/示例代码/标注样式和几何绘制。
    /// 内容：提供创建标注样式、文字样式及绘制几何图形的功能示例。
    /// 功能：
    /// - 创建标注样式并设置相关属性（如文字样式、尺寸、对齐方式等）。
    /// - 创建文字样式并设置其属性（如宽度、高度、颜色等）。
    /// - 绘制几何图形（如直线段）并添加到场景中。
    /// 关键类及说明：
    /// - **ATDimensionObject** 类用于表示图形平台中的标注对象。
    /// - **ATTextStyle**: 用于创建和设置文字样式。
    /// - **DimensionStyle**: 用于创建和设置标注样式。
    /// - **XPoint3d**: 表示三维空间中的点，常用于几何计算。
    /// - **CurveSet**: 用于存储和管理几何曲线对象。
    /// - **ATObject**: 代表图形对象，支持添加到场景中。
    /// 注意：
    /// - 确保属性设置符合平台要求，并且操作工程中的对象有效。
    /// </summary>
    public class CreateDimension
    {
        // 标注样式的默认名称
        private static string dimStyleName = "DimStyle";

        // 文字样式的默认名称
        private static string txtStyName = "标注使用的文字样式";

        // 用于存储线性标注对象
        private static ATDimensionObject dimObj_Linear = null;

        // 用于存储角度标注对象
        private static ATDimensionObject dimObj_Angle = null;

        /// <summary>
        /// 获取或创建文字样式
        /// 功能：根据提供的名称获取现有的文字样式，如果不存在则创建一个新的文字样式
        /// </summary>
        /// <param name="nm">文字样式的名称</param>
        /// <returns>返回创建或找到的文字样式</returns>
        public static ATTextStyle CreateTextStyle(string nm)
        {
            // 获取当前活动项目
            ATProject activeProj = ATEC.ATCore.Session.Entity.GetActiveATProject();

            // 查找是否已存在指定名称的文字样式
            ATTextStyle txtStyle = ATTextStyle.GetByName(nm, activeProj);
            if (txtStyle != null)
            {
                return txtStyle; // 如果存在，直接返回现有文字样式
            }

            // 如果文字样式不存在，则创建新的文字样式
            txtStyle = new ATTextStyle(nm, activeProj);
            {
                // 设置文字样式的属性：宽度、高度、颜色
                txtStyle.SetProperty(TextStyleProperty.Width, (double)500); // 设置宽度为500 uor
                txtStyle.SetProperty(TextStyleProperty.Height, (double)500); // 设置高度为500 uor
                txtStyle.SetProperty(TextStyleProperty.ColorFlag, true); // 启用颜色标志
                txtStyle.SetProperty(TextStyleProperty.Color, (UInt32)3); // 设置颜色为3
            }
            txtStyle.Add(activeProj); // 将新创建的文字样式添加到当前项目中

            return txtStyle;
        }

        /// <summary>
        /// 创建标注样式
        /// 功能：根据给定名称创建一个新的标注样式，设置相关的属性
        /// </summary>
        /// <param name="nm">标注样式的名称</param>
        /// <returns>返回创建的标注样式</returns>
        public static DimensionStyle CreateDimensionStyle(string nm)
        {
            // 根据名称从当前项目中查找是否已有该标注样式
            var dimStyle = DimensionStyle.GetByName(dimStyleName, Session.Entity.GetActiveATProject());
            if (dimStyle != null)
            {
                return dimStyle; // 如果已存在，直接返回
            }

            // 创建新的标注样式
            dimStyle = new DimensionStyle(nm, Session.Entity.GetActiveATProject());
            {
                // 设置标注样式的各项属性
                dimStyle.SetBooleanProp(true, DimStyleProp.Placement_UseStyleAnnotationScale_BOOLINT); // 启用标注样式比例
                dimStyle.SetDoubleProp(1, DimStyleProp.Placement_AnnotationScale_DOUBLE); // 设置比例值为1

                dimStyle.SetBooleanProp(true, DimStyleProp.Text_OverrideHeight_BOOLINT); // 启用文字高度覆盖
                double textHeight = 0.5 * 10000; // 设置文字高度为0.5m
                dimStyle.SetDistanceProp(textHeight, DimStyleProp.Text_Height_DISTANCE, Session.Entity.GetActiveATScenes());

                dimStyle.SetBooleanProp(true, DimStyleProp.Text_OverrideWidth_BOOLINT); // 启用文字宽度覆盖
                double textWidth = 0.4 * 10000; // 设置文字宽度为0.4m
                dimStyle.SetDistanceProp(textWidth, DimStyleProp.Text_Width_DISTANCE, Session.Entity.GetActiveATScenes());

                int alignInt = (int)DimStyleProp_General_Alignment.True; // 设置文字对齐方式
                StatusInt status = dimStyle.SetIntegerProp(alignInt, DimStyleProp.General_Alignment_INTEGER);

                dimStyle.SetBooleanProp(true, DimStyleProp.Value_AngleMeasure_BOOLINT); // 启用角度测量

                double extenLen = 0.5; // 设置尺寸引线的延长长度
                dimStyle.SetDoubleProp(extenLen, DimStyleProp.ExtensionLine_Extend_DOUBLE);

                double offsetDis = 0.01; // 设置尺寸引线的偏移值
                dimStyle.SetDoubleProp(offsetDis, DimStyleProp.ExtensionLine_Offset_DOUBLE);
            }
            dimStyle.Add(Session.Entity.GetActiveATProject()); // 将创建的标注样式添加到项目中

            return dimStyle;
        }

        /// <summary>
        /// 绘制直线段
        /// 功能：绘制一条直线段并返回该线的起点和终点坐标
        /// </summary>
        /// <returns>返回直线段的起点和终点坐标</returns>
        private static List<XPoint3d> DrawLine()
        {
            ATProject project;

            // 定义直线的起点和终点坐标
            XPoint3d startPoint = XPoint3d.FromXYZ(300000, 0, 0); // 起点
            XPoint3d endPoint = XPoint3d.FromXYZ(400000, 0, 0); // 终点

            // 创建曲线集合对象
            CurveSet curve = CurveSet.Create(CurveSet.BoundaryType.None);

            // 创建并添加直线段到曲线集合
            curve.Add(BasicCurve.CreateLine(new XSegment3d(startPoint, endPoint)));

            // 将曲线集合转换为ATObject对象，并添加到场景中
            ATObject curveObj = GeometryToATObject.ToObject(Session.Entity.GetActiveATScenes(), curve, null);
            {
                // 设置曲线的颜色
                ObjectPropertiesSetter setter = new ObjectPropertiesSetter();
                setter.SetColor((uint)3); // 设置颜色为3
                setter.Apply(curveObj);
            }
            curveObj.AddToScene(); // 将曲线对象添加到当前场景

            // 返回起点和终点坐标
            return new List<XPoint3d> { startPoint, endPoint };
        }

        /// <summary>
        /// 创建一个线性标注示例
        /// 通过代码创建标注样式并在模型中绘制一条线性标注
        /// </summary>
        public static void CreateLinerDimension()
        {
            // 画一条直线
            List<XPoint3d> listPt = DrawLine();

            // 准备数据，设置标注样式、文字样式、图层、符号学等属性
            DimensionProperty createData = new DimensionProperty()
            {
                m_dimstyle = CreateDimensionStyle(dimStyleName), // 设置标注样式
                m_textStyle = CreateTextStyle(txtStyName),       // 设置文字样式
                m_levelId = Session.Entity.GetActiveATProject().GetLevelCache().GetLevelByName("Default").LevelId, // 设置图层为"Default"
                m_symbology = new Symbology(),                   // 默认符号学设置
                m_dimMatrix = XMatrix3d.Identity,                // 设置dimMatrix
                m_viewMatrix = XMatrix3d.Identity,               // 设置viewMatrix
            };

            // 创建标注对象
            dimObj_Linear = new ATDimensionObject(Session.Entity.GetActiveATScenes(), createData, DimensionType.SizeArrow);
            if (dimObj_Linear.IsValid) // 判断标注对象是否有效
            {
                // 设置标注点
                dimObj_Linear.InsertPoint(listPt[0], null, createData.GetDimensionStyle(), -1); // 插入起始点
                dimObj_Linear.InsertPoint(listPt[1], null, createData.GetDimensionStyle(), -1); // 插入终止点

                // 设置标注高度
                dimObj_Linear.SetHeight(5000);

                // 设置标注旋转矩阵
                dimObj_Linear.SetRotationMatrix(XMatrix3d.Identity);

                // 将标注对象添加到场景中
                dimObj_Linear.AddToScene();
            }
        }

        /// <summary>
        /// 修改线性标注文本
        /// 如果线性标注对象有效且未删除，则调用文本替换方法
        /// </summary>
        public static void ModifyText_Linear()
        {
            if (dimObj_Linear != null && dimObj_Linear.IsValid && !dimObj_Linear.IsDeleted)
            {
                // 替换标注文本
                ReplaceDimensionText(ref dimObj_Linear);
            }
        }

        /// <summary>
        /// 以给定的角点为基准，绘制一个角度标注
        /// vec1为起始边，angle为旋转角度
        /// </summary>
        /// <param name="corner">角点坐标</param>
        /// <param name="vec1">起始边向量</param>
        /// <param name="angle">旋转角度</param>
        /// <returns>返回角度标注的三个关键点</returns>
        private static List<XPoint3d> DrawAngle(XPoint3d corner, XVector3d vec1, XAngle angle)
        {
            // 创建曲线集合
            CurveSet curve = CurveSet.Create(CurveSet.BoundaryType.None);

            // 添加第一条边
            curve.Add(BasicCurve.CreateLine(new XSegment3d(corner, corner + vec1 * 10e4)));

            // 计算并添加第二条边
            XVector3d vec2 = vec1.RotateXY(angle); // 绕XY平面旋转指定角度
            curve.Add(BasicCurve.CreateLine(new XSegment3d(corner, corner + vec2 * 10e4)));

            // 获取当前激活的模型空间
            ATSceneRef sceneref = SSDPNET.ScenesFunctions.SceneRefGetActive();

            // 将曲线集合转换为ATObject对象
            ATObject curveObj = GeometryToATObject.ToObject(sceneref.GetATScene(), curve, null);

            // 设置对象属性，如颜色
            ObjectPropertiesSetter setter = new ObjectPropertiesSetter();
            setter.SetColor((uint)3); // 设置颜色为3
            setter.Apply(curveObj);

            // 将曲线对象添加到场景中
            curveObj.AddToScene();

            // 返回角点和两条边的端点
            return new List<XPoint3d> { corner, corner + vec1 * 8e4, corner + vec2 * 8e4 };
        }

        /// <summary>
        /// 创建一个角度标注示例
        /// 通过代码创建标注样式并在模型中绘制角度标注
        /// </summary>
        public static void CreateAngleDimension()
        {
            // 画角度标注
            XPoint3d corner = XPoint3d.FromXYZ(1e4, 1e4, 0);  // 角点位置
            XVector3d vec = XVector3d.FromXYZ(1, 1, 0);       // 起始边向量
            List<XPoint3d> listPts = DrawAngle(corner, vec, XAngle.FromDegrees(102.6)); // 绘制角度

            // 准备属性，设置标注样式、文字样式、图层等信息
            DimensionProperty createData = new DimensionProperty()
            {
                m_dimstyle = CreateDimensionStyle(dimStyleName),  // 设置标注样式
                m_textStyle = CreateTextStyle(txtStyName),        // 设置文字样式
                m_levelId = Session.Entity.GetActiveATProject().GetLevelCache().GetLevelByName("Default").LevelId, // 设置图层为"Default"
                m_symbology = new Symbology(),                    // 符号学设置
                m_dimMatrix = XMatrix3d.Identity,                 // 设置dimMatrix
                m_viewMatrix = XMatrix3d.Identity,                // 设置viewMatrix
            };

            // 创建角度标注对象
            dimObj_Angle = new ATDimensionObject(Session.Entity.GetActiveATScenes(), createData, DimensionType.AngleSize);
            if (dimObj_Angle.IsValid) // 判断标注对象是否有效
            {
                // 插入标注点
                dimObj_Angle.InsertPoint(listPts[0], null, createData.GetDimensionStyle(), -1); // 插入角点
                dimObj_Angle.InsertPoint(listPts[1], null, createData.GetDimensionStyle(), -1); // 插入起始边点
                dimObj_Angle.InsertPoint(listPts[2], null, createData.GetDimensionStyle(), -1); // 插入终止边点

                // 设置标注高度
                dimObj_Angle.SetHeight(100);

                // 设置标注旋转矩阵
                dimObj_Angle.SetRotationMatrix(XMatrix3d.Identity);

                // 将角度标注对象添加到场景中
                dimObj_Angle.AddToScene();
            }
        }

        /// <summary>
        /// 创建半径、直径标注示例
        /// 通过判断半径标注对象是否有效，调用 `ReplaceDimensionText` 方法替换标注文本
        /// </summary>
        public static void ModifyText_Angle()
        {
            // 检查角度标注对象是否有效且未被删除
            if (dimObj_Angle != null && dimObj_Angle.IsValid && !dimObj_Angle.IsDeleted)
            {
                // 替换角度标注的文字
                ReplaceDimensionText(ref dimObj_Angle);
            }
        }

        /// <summary>
        /// 绘制圆形，返回标注需要的点：中心点、弧上点、中心点偏移一段距离点
        /// 该方法用于绘制圆并准备标注所需的关键点
        /// </summary>
        /// <returns>返回三个关键点：中心点、弧上点、中心点偏移后的点</returns>
        private static List<XPoint3d> DrawCircle()
        {
            List<XPoint3d> R = null;  // 返回的标注点列表

            // 创建一个空的曲线集合
            var curve = CurveSet.Create(CurveSet.BoundaryType.None);

            {
                // 定义圆心、法线方向以及圆的半径
                var center = new XPoint3d(600000, 80000, 0);  // 圆心位置
                XVector3d normal = new XVector3d(0, 0, 1);   // 法线方向
                var dEllipse3d = XEllipse3d.FromCenterRadiusNormal(center, 40000, normal);  // 创建圆对象

                // 将圆加入到曲线集合中
                curve.Add(BasicCurve.CreateArc(dEllipse3d));

                // 获取圆弧上的起始点
                XPoint3d arcPt;
                curve.GetStartPoint(out arcPt); // 获取弧上点
                XVector3d radiusVec = SSDPNET.Geom.XVector3dExtension.FromStartEnd(dEllipse3d.Center, arcPt);  // 计算圆心到弧上点的向量
                XPoint3d centerOffset = dEllipse3d.Center + radiusVec * 0.2;  // 偏移圆心点

                // 返回三个标注需要的点：中心点、弧上点、偏移后的中心点
                R = new List<XPoint3d> { dEllipse3d.Center, arcPt, centerOffset };
            }

            // 将曲线集合转换为 ATObject 对象
            ATObject curveObj = GeometryToATObject.ToObject(Session.Entity.GetActiveATScenes(), curve, null);

            {
                // 设置曲线对象的属性，例如颜色
                ObjectPropertiesSetter setter = new ObjectPropertiesSetter();
                setter.SetColor((uint)3);  // 设置颜色为3
                setter.Apply(curveObj);    // 应用属性
            }

            // 将曲线对象添加到场景中
            curveObj.AddToScene();

            return R;  // 返回标注所需的三个点
        }

        /// <summary>
        /// 创建半径标注对象并将其添加到模型中
        /// </summary>
        public static void CreateRadiusDimension()
        {
            // 绘制圆形并获取标注所需的点
            List<XPoint3d> listPt = DrawCircle();

            // 创建标注属性
            DimensionProperty createData = new DimensionProperty()
            {
                m_dimstyle = CreateDimensionStyle(dimStyleName),   // 设置标注样式
                m_textStyle = CreateTextStyle(txtStyName),          // 设置文字样式
                m_levelId = Session.Entity.GetActiveATProject().GetLevelCache().GetLevelByName("Default").LevelId,  // 设置图层
                m_symbology = new Symbology(),                      // 设置符号学属性
                m_dimMatrix = XMatrix3d.Identity,                   // 设置维度矩阵
                m_viewMatrix = XMatrix3d.Identity,                  // 设置视图矩阵
            };

            // 创建半径标注对象，类型为半径标注
            ATDimensionObject dimObj = new ATDimensionObject(Session.Entity.GetActiveATScenes(), createData, dimType: DimensionType.Radius);

            if (dimObj.IsValid)  // 判断标注对象是否有效
            {
                // 插入标注点：中心点、弧上点、中心点偏移点
                dimObj.InsertPoint(listPt[0], null, createData.GetDimensionStyle(), -1);  // 插入中心点
                dimObj.InsertPoint(listPt[1], null, createData.GetDimensionStyle(), -1);  // 插入弧上点
                dimObj.InsertPoint(listPt[2], null, createData.GetDimensionStyle(), -1);  // 插入偏移点

                // 设置标注的高度
                dimObj.SetHeight(100);

                // 设置标注的旋转矩阵
                dimObj.SetRotationMatrix(XMatrix3d.Identity);

                // 将标注对象添加到场景中
                dimObj.AddToScene();
            }
        }

        /// <summary>
        /// 替换标注对象的文字内容
        /// 通过文本编辑器获取和替换标注的文字
        /// </summary>
        /// <param name="dimObj">标注对象</param>
        public static void ReplaceDimensionText(ref ATDimensionObject dimObj)
        {
            // 获取标注对象的文本编辑器
            TextEdit edit = dimObj.AsTextEdit();
            if (edit == null)
            {
                return;  // 如果没有文本编辑器，则不进行替换
            }

            // 获取标注中的第一个文本部分
            TextBlock tb = TextHandlerBaseExtension.GetFirstTextPartValue(dimObj);
            if (tb == null)
            {
                return;  // 如果没有文本部分，则不进行替换
            }

            // 创建替换文本
            string replaceText = "替换文字-" + tb.ToString();
            tb.ReplaceText(replaceText, tb.CreateStartATCaret(), tb.CreateEndATCaret());  // 替换文本

            // 获取文本部分并进行替换操作
            TextPartIdCollection collection = edit.GetTextPartIds(new TextQueryOptions());
            if (collection.Count() > 0)
            {
                TextPartId prt = collection[0];
                if (TextReplaceStatus.Success != edit.ReplaceTextPart(prt, tb))
                {
                    // 如果替换失败，输出错误信息
                    SSDPNET.ATOutputFuncs.OutputMessageCenter(SSDPNET.ATOutputFuncs.OutputMessagePriority.Error, "替换失败！", "替换标注文字失败", SSDPNET.ATOutputFuncs.OutputMessageAlert.Balloon);
                }
            }

            // 更新标注对象中的文本
            edit.ReplaceInScene(dimObj);
        }

        /// <summary>
        /// 调用方法创建线性标注
        /// </summary>
        public static void LineDim()
        {
            CreateLinerDimension();  // 创建线性标注
        }

        /// <summary>
        /// 调用方法创建角度标注
        /// </summary>
        public static void AngleDim()
        {
            CreateAngleDimension();  // 创建角度标注
        }

        /// <summary>
        /// 调用方法创建半径标注
        /// </summary>
        public static void radiusDim()
        {
            CreateRadiusDimension();  // 创建半径标注
        }

    }

}
